package com.webchat.aigc.service;


import com.webchat.aigc.repository.dao.IBotDAO;
import com.webchat.aigc.repository.dao.IBotPluginDAO;
import com.webchat.aigc.repository.entity.BotEntity;
import com.webchat.aigc.repository.entity.BotPluginEntity;
import com.webchat.common.enums.CommonStatusEnum;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.service.RedisService;
import com.webchat.common.util.JsonUtil;
import com.webchat.domain.dto.bot.BotBaseDTO;
import com.webchat.domain.dto.bot.BotDTO;
import com.webchat.domain.dto.bot.BotPluginDTO;
import com.webchat.domain.vo.request.bot.SaveBotRequestVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Service
public class BotService {

    @Autowired
    private IBotDAO botDAO;
    @Autowired
    private IBotPluginDAO botPluginDAO;

    @Autowired
    private RedisService redisService;

    public Long saveBot(SaveBotRequestVO botRequestVO) {
        BotEntity botEntity = this.convert(botRequestVO);
        botEntity = botDAO.save(botEntity);
        return botEntity.getId();
    }

    public boolean publish(Long botId, String operator) {
        BotEntity botEntity = botDAO.findById(botId).orElse(null);
        Assert.notNull(botEntity, "发布失败：没查询到插件");
        BotPluginEntity botPluginEntity = findPluginByBotCodeFromDB(botEntity.getCode());
        Assert.notNull(botPluginEntity, "发布失败：未检查到API配置");
        botEntity.setStatus(CommonStatusEnum.PUBLISHED.getStatusCode());
        botDAO.save(botEntity);
        /**
         * 刷新插件相关缓存
         */
        this.refreshBotAboutCache(botId);
        log.info("【插件状态更新】===> {} 发布了插件 {}", operator, botEntity.getName());
        return true;
    }

    public boolean offline(Long botId, String operator) {
        BotEntity botEntity = botDAO.findById(botId).orElse(null);
        Assert.notNull(botEntity, "发布失败：没查询到插件");
        botEntity.setStatus(CommonStatusEnum.BACK.getStatusCode());
        botDAO.save(botEntity);
        /**
         * 刷新插件相关缓存
         */
        this.refreshBotAboutCache(botId);
        log.info("【插件状态更新】===> {} 下线了插件 {}", operator, botEntity.getName());
        return true;
    }

    /**
     * 查询插件详情，走redis
     *
     * @param botCode
     * @return
     */
    public BotDTO getBotPluginFromCache(String botCode) {
        String key = botCacheKey(botCode);
        String cache = redisService.get(key);
        if (StringUtils.isNotBlank(cache)) {
            return JsonUtil.fromJson(cache, BotDTO.class);
        }
        return this.refreshBotDetailConfigCache(botCode);
    }

    /**
     * 走redis批量查询所有已经发布的插件详情
     *
     * @return
     */
    public List<BotDTO> getPublishBotDetailFromCache() {
        List<String> codes = this.getPublishBotCodes();
        if (CollectionUtils.isEmpty(codes)) {
            return Collections.emptyList();
        }
        List<BotDTO> botDTOList = new ArrayList<>();
        List<String> keys = codes.stream().map(c -> botCacheKey(c)).collect(Collectors.toList());
        List<String> caches = redisService.mget(keys);
        for (int i = 0; i < codes.size(); i++) {
            String code = codes.get(i);
            String cache = caches.get(i);
            BotDTO botDTO;
            if (StringUtils.isNotBlank(cache)) {
                botDTO = JsonUtil.fromJson(cache, BotDTO.class);
            } else {
                botDTO = this.refreshBotDetailConfigCache(code);
            }
            botDTOList.add(botDTO);
        }
        return botDTOList;
    }

    /**
     * 查询所有已经发布的插件code标识列表，走redis
     *
     * @return
     */
    public List<String> getPublishBotCodes() {
        String key = RedisKeyEnum.AI_BOT_PLUGIN_CODE_LIST_CACHE.getKey();
        List<String> codes = redisService.lrange(key, 0, Integer.MAX_VALUE);
        if (CollectionUtils.isNotEmpty(codes)) {
            return codes;
        }
        return this.refreshBotListCache();
    }

    private void refreshBotAboutCache(Long botId) {
        // 刷新插件详情缓存
        this.refreshBotDetailConfigCache(botId);
        // 刷新bot列表缓存
        this.refreshBotListCache();
    }

    /**
     * By 插件code刷新插件配置详情缓存
     *
     * @param botCode
     * @return
     */
    private BotDTO refreshBotDetailConfigCache(String botCode) {
        BotEntity botEntity = botDAO.findAllByCode(botCode);
        return this.refreshBotDetailConfigCache(botEntity);
    }

    /**
     * By 插件id刷新插件配置详情缓存
     *
     * @param botId
     * @return
     */
    private BotDTO refreshBotDetailConfigCache(Long botId) {
        BotEntity botEntity = botDAO.findById(botId).orElse(null);
        return this.refreshBotDetailConfigCache(botEntity);
    }

    private BotDTO refreshBotDetailConfigCache(BotEntity botEntity) {
        if (botEntity == null) {
            return null;
        }
        String botCode = botEntity.getCode();
        BotDTO botDTO = new BotDTO();
        BeanUtils.copyProperties(botEntity, botDTO);
        // 查询插件信息
        BotPluginEntity botPluginEntity = botPluginDAO.findAllByBotCode(botCode);
        if (botPluginEntity != null) {
            BotPluginDTO botPluginDTO = new BotPluginDTO();
            BeanUtils.copyProperties(botPluginEntity, botPluginDTO);
            botDTO.setPlugin(botPluginDTO);
        }
        String key = botCacheKey(botCode);
        redisService.set(key, JsonUtil.toJsonString(botDTO), RedisKeyEnum.AI_BOT_PLUGIN_DETAIL_CACHE.getExpireTime());
        return botDTO;
    }

    private String botCacheKey(String botCode) {
        return RedisKeyEnum.AI_BOT_PLUGIN_DETAIL_CACHE.getKey(botCode);
    }

    private BotPluginEntity findPluginByBotCodeFromDB(String botCode) {
        return botPluginDAO.findAllByBotCode(botCode);
    }

    /**
     * 刷新已经发布的插件code表示列表缓存
     *
     * @return
     */
    private List<String> refreshBotListCache() {
        List<String> publishBotCodes = botDAO.findAllBotCodeAndStatus(CommonStatusEnum.PUBLISHED.getStatusCode());
        publishBotCodes = publishBotCodes == null ? Collections.emptyList() : publishBotCodes;
        String key = RedisKeyEnum.AI_BOT_PLUGIN_CODE_LIST_CACHE.getKey();
        redisService.lleftPushAll(key, publishBotCodes);
        return publishBotCodes;
    }

    private BotEntity convert(SaveBotRequestVO botRequestVO) {
        Long id = botRequestVO.getId();
        Date now = new Date();
        BotEntity botEntity;
        if (id != null) {
            botEntity = botDAO.findById(id).orElse(null);
            Assert.notNull(botEntity, "更新失败：没查询到插件");
        } else {
            botEntity = new BotEntity();
            botEntity.setCreateDate(now);
            botEntity.setCreateBy(botRequestVO.getUserId());
            botEntity.setStatus(CommonStatusEnum.NEW.getStatusCode());
        }

        botEntity.setName(botRequestVO.getName());
        botEntity.setDescription(botRequestVO.getDescription());
        botEntity.setCode(botRequestVO.getCode());
        botEntity.setRule(botRequestVO.getRule());
        botEntity.setSchema(botRequestVO.getSchema());
        botEntity.setOutputExample(botRequestVO.getOutputExample());
        return botEntity;
    }
}
